<!--
  Vue3 Screen Adapter - 独立版本
  可以直接复制到任何Vue3项目中使用
  
  使用方法:
  <ScreenAdapter :design-width="1920" :design-height="1080" mode="scale">
    <div>您的大屏内容</div>
  </ScreenAdapter>
-->
<template>
  <div
    class="screen-adapter"
    :class="[
      `screen-adapter--${mode}`,
      {
        'screen-adapter--ready': isReady,
        'screen-adapter--loading': !isReady && showLoading,
        'screen-adapter--debug': debug,
      },
    ]"
  >
    <div ref="screenContainer" class="screen-container" :style="containerStyle">
      <!-- 加载状态 -->
      <div v-if="!isReady && showLoading" class="screen-loading">
        <slot name="loading" :loading-text="loadingText">
          <div class="default-loading">
            <div class="loading-spinner"></div>
            <p class="loading-text">{{ loadingText }}</p>
          </div>
        </slot>
      </div>

      <!-- 主要内容 -->
      <div v-show="isReady || !showLoading" class="screen-content">
        <slot :scale-info="currentScaleInfo" :is-ready="isReady"></slot>
      </div>

      <!-- 错误状态 -->
      <div v-if="hasError" class="screen-error">
        <slot name="error" :error="errorInfo" :retry="handleRetry">
          <div class="default-error">
            <div class="error-icon">⚠️</div>
            <p class="error-message">
              {{ errorInfo.message || "大屏加载失败" }}
            </p>
            <button class="error-retry-btn" @click="handleRetry">重试</button>
          </div>
        </slot>
      </div>

      <!-- 调试信息 -->
      <div v-if="debug" class="debug-panel">
        <div class="debug-content">
          <h4>🔧 调试信息</h4>
          <div class="debug-item">
            <span>设计尺寸:</span>
            <span>{{ designWidth }} × {{ designHeight }}</span>
          </div>
          <div class="debug-item">
            <span>当前窗口:</span>
            <span>{{ currentWidth }} × {{ currentHeight }}</span>
          </div>
          <div class="debug-item">
            <span>缩放比例:</span>
            <span>{{ currentScaleInfo.ratio?.toFixed(3) || "N/A" }}</span>
          </div>
          <div class="debug-item">
            <span>适配模式:</span>
            <span>{{ mode }}</span>
          </div>
        </div>
      </div>
    </div>

    <!-- 全屏背景 -->
    <div
      v-if="fullscreen && background"
      class="screen-background"
      :style="backgroundStyle"
    ></div>
  </div>
</template>

<script>
export default {
  name: "ScreenAdapter",
  props: {
    designWidth: { type: Number, default: 1920 },
    designHeight: { type: Number, default: 1080 },
    mode: {
      type: String,
      default: "scale",
      validator: (value) => ["scale", "fit", "full", "rem"].includes(value),
    },
    maxScale: { type: Number, default: 3 },
    minScale: { type: Number, default: 0.3 },
    remBase: { type: Number, default: 16 },
    debounceTime: { type: Number, default: 100 },
    showLoading: { type: Boolean, default: true },
    loadingText: { type: String, default: "大屏加载中..." },
    autoInit: { type: Boolean, default: true },
    debug: { type: Boolean, default: false },
    fullscreen: { type: Boolean, default: true },
    background: { type: String, default: "" },
  },

  data() {
    return {
      isReady: false,
      hasError: false,
      errorInfo: {},
      currentWidth: 0,
      currentHeight: 0,
      currentScaleInfo: {},
      resizeObserver: null,
      debouncedResize: null,
    };
  },

  computed: {
    containerStyle() {
      const style = {
        width: `${this.designWidth}px`,
        height: `${this.designHeight}px`,
        transformOrigin: "0 0",
        position: "fixed",
        left: "50%",
        top: "50%",
        transition: "all 0.3s ease",
      };

      if (this.currentScaleInfo.scaleX && this.currentScaleInfo.scaleY) {
        if (this.mode !== "rem") {
          style.transform = `scale(${this.currentScaleInfo.scaleX}, ${this.currentScaleInfo.scaleY}) translate(-50%, -50%)`;
        } else {
          style.transform = "translate(-50%, -50%)";
        }
      }

      return style;
    },

    backgroundStyle() {
      return {
        position: "fixed",
        top: 0,
        left: 0,
        width: "100vw",
        height: "100vh",
        background: this.background,
        zIndex: -1,
      };
    },
  },

  mounted() {
    if (this.autoInit) {
      this.init();
    }
  },

  beforeUnmount() {
    this.destroy();
  },

  methods: {
    init() {
      try {
        this.setupResize();
        this.updateScreenInfo();
        this.isReady = true;
        this.hasError = false;
        this.$emit("ready", this.currentScaleInfo);
      } catch (error) {
        this.handleError(error);
      }
    },

    destroy() {
      if (this.resizeObserver) {
        this.resizeObserver.disconnect();
      }
      window.removeEventListener("resize", this.debouncedResize);
      window.removeEventListener("orientationchange", this.debouncedResize);

      if (this.mode === "rem") {
        document.documentElement.style.fontSize = "";
      }
    },

    setupResize() {
      this.debouncedResize = this.debounce(() => {
        this.updateScreenInfo();
      }, this.debounceTime);

      window.addEventListener("resize", this.debouncedResize);
      window.addEventListener("orientationchange", this.debouncedResize);

      // 使用ResizeObserver监听容器变化
      if (window.ResizeObserver && this.$refs.screenContainer) {
        this.resizeObserver = new ResizeObserver(this.debouncedResize);
        this.resizeObserver.observe(this.$refs.screenContainer);
      }
    },

    updateScreenInfo() {
      const windowSize = this.getWindowSize();
      this.currentWidth = windowSize.width;
      this.currentHeight = windowSize.height;

      const scaleInfo = this.calculateScale(
        windowSize.width,
        windowSize.height
      );
      this.currentScaleInfo = {
        ...scaleInfo,
        windowWidth: windowSize.width,
        windowHeight: windowSize.height,
        mode: this.mode,
      };

      this.$emit("scale-change", this.currentScaleInfo);
    },

    getWindowSize() {
      return {
        width: window.innerWidth || document.documentElement.clientWidth,
        height: window.innerHeight || document.documentElement.clientHeight,
      };
    },

    calculateScale(windowWidth, windowHeight) {
      const scaleX = windowWidth / this.designWidth;
      const scaleY = windowHeight / this.designHeight;

      let finalScaleX, finalScaleY;

      switch (this.mode) {
        case "fit":
          const minScale = Math.min(scaleX, scaleY);
          finalScaleX = finalScaleY = Math.max(
            this.minScale,
            Math.min(this.maxScale, minScale)
          );
          break;
        case "full":
          const maxScale = Math.max(scaleX, scaleY);
          finalScaleX = finalScaleY = Math.max(
            this.minScale,
            Math.min(this.maxScale, maxScale)
          );
          break;
        case "rem":
          const remScale = Math.min(scaleX, scaleY);
          this.setRootFontSize(remScale);
          finalScaleX = finalScaleY = 1;
          break;
        case "scale":
        default:
          finalScaleX = Math.max(
            this.minScale,
            Math.min(this.maxScale, scaleX)
          );
          finalScaleY = Math.max(
            this.minScale,
            Math.min(this.maxScale, scaleY)
          );
          break;
      }

      return {
        scaleX: finalScaleX,
        scaleY: finalScaleY,
        ratio: Math.min(finalScaleX, finalScaleY),
        originalScaleX: scaleX,
        originalScaleY: scaleY,
      };
    },

    setRootFontSize(scale) {
      const fontSize = this.remBase * scale;
      document.documentElement.style.fontSize = `${fontSize}px`;
    },

    handleError(error) {
      this.hasError = true;
      this.errorInfo = {
        message: error.message || "未知错误",
        code: error.code || "UNKNOWN_ERROR",
        timestamp: new Date().toISOString(),
      };
      this.$emit("error", this.errorInfo);
      console.error("ScreenAdapter Error:", error);
    },

    handleRetry() {
      this.hasError = false;
      this.errorInfo = {};
      this.init();
      this.$emit("retry");
    },

    debounce(func, wait) {
      let timeout;
      return function executedFunction(...args) {
        const later = () => {
          clearTimeout(timeout);
          func.apply(this, args);
        };
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
      };
    },

    // 公共方法
    refresh() {
      this.updateScreenInfo();
    },

    updateMode(mode) {
      if (["scale", "fit", "full", "rem"].includes(mode)) {
        this.$emit("update:mode", mode);
        this.$nextTick(() => {
          this.updateScreenInfo();
        });
      }
    },
  },
};
</script>

<style scoped>
.screen-adapter {
  position: relative;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  background: #000;
}

.screen-container {
  position: relative;
  box-sizing: border-box;
}

.screen-content {
  width: 100%;
  height: 100%;
}

/* 加载状态 */
.screen-loading {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  color: white;
  background: rgb(0 0 0 / 80%);
}

.default-loading {
  text-align: center;
}

.loading-spinner {
  width: 40px;
  height: 40px;
  margin: 0 auto 20px;
  border: 4px solid #333;
  border-top: 4px solid #4fc3f7;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }

  100% {
    transform: rotate(360deg);
  }
}

.loading-text {
  margin: 0;
  font-size: 16px;
  opacity: 0.8;
}

/* 错误状态 */
.screen-error {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1001;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  color: white;
  background: rgb(0 0 0 / 90%);
}

.default-error {
  padding: 40px;
  text-align: center;
}

.error-icon {
  margin-bottom: 20px;
  font-size: 48px;
}

.error-message {
  margin-bottom: 30px;
  font-size: 16px;
  opacity: 0.8;
}

.error-retry-btn {
  padding: 10px 20px;
  font-size: 14px;
  color: white;
  cursor: pointer;
  background: #4caf50;
  border: none;
  border-radius: 4px;
  transition: background 0.3s;
}

.error-retry-btn:hover {
  background: #45a049;
}

/* 调试面板 */
.debug-panel {
  position: fixed;
  top: 20px;
  right: 20px;
  z-index: 9999;
  min-width: 200px;
  padding: 15px;
  font-family: "Courier New", monospace;
  font-size: 12px;
  color: white;
  background: rgb(0 0 0 / 80%);
  border-radius: 8px;
}

.debug-content h4 {
  margin: 0 0 10px;
  font-size: 14px;
  color: #4fc3f7;
}

.debug-item {
  display: flex;
  justify-content: space-between;
  padding: 2px 0;
  margin-bottom: 5px;
}

.debug-item span:first-child {
  opacity: 0.7;
}

/* 背景 */
.screen-background {
  pointer-events: none;
}

/* 模式样式 */
.screen-adapter--scale .screen-container {
  /* scale 模式特定样式 */
}

.screen-adapter--fit .screen-container {
  /* fit 模式特定样式 */
}

.screen-adapter--full .screen-container {
  /* full 模式特定样式 */
}

.screen-adapter--rem .screen-container {
  /* rem 模式特定样式 */
}

/* 状态样式 */
.screen-adapter--ready {
  /* 准备状态样式 */
}

.screen-adapter--loading {
  /* 加载状态样式 */
}

.screen-adapter--debug {
  /* 调试模式样式 */
}

/* 响应式 */
@media (width <= 768px) {
  .debug-panel {
    top: 10px;
    right: 10px;
    min-width: 150px;
    padding: 10px;
    font-size: 10px;
  }
}
</style>
